#ifndef ZG_SHAREDPTR_H
#define ZG_SHAREDPTR_H

#include "memory"
namespace zg_util {

#if __cplusplus >= 201103L
    template <typename T> using SharePtr=std::shared_ptr<T> ;
#else
    template<typename T>
    class SharedPtr {
    public:
        SharedPtr<T>(T *pdata) : _data(pdata) {
            _reference_count = new int;
            *_reference_count = 1;
        }

        SharedPtr<T>(const SharedPtr<T> &p) {

            if (p._reference_count)
                __sync_fetch_and_add(p._reference_count, 1);
            _reference_count = p._reference_count;
            printf("%d %d\n", *(p._reference_count), *_reference_count);
            _data = p._data;
        }

        T *get() {
            return _data;
        }

        SharedPtr() {
            _data = NULL;
            _reference_count = NULL;
        }

        ~SharedPtr() {
            if (_reference_count) {
                __sync_fetch_and_sub(_reference_count, 1);
            } else {
                return;
            }
            if (*_reference_count == 0) {
                delete _data;
                delete (_reference_count);
            }
        }

        void operator=(SharedPtr &p) {
            __sync_fetch_and_add(p._reference_count, 1);
            if (_reference_count) {
                __sync_fetch_and_sub(_reference_count, 1);
                if (*_reference_count == 0) {
                    delete _data;
                    delete _reference_count;
                    _reference_count = NULL;
                    _data = NULL;
                }
            } else {
                _reference_count = new int;
                *_reference_count = 1;
            }
            _data = p._data;
        }

        void operator=(T *const t) {

            __sync_fetch_and_sub(_reference_count, 1);
            if (*_reference_count == 0) {
                delete _data;
                delete (_reference_count);
            } else if (*_reference_count < 0) {
                return;
            }
            _reference_count = new int;
            *_reference_count = 1;
            _data = t;
        }

    private:
        T *_data;
        int *_reference_count;
    };
#endif
}
#endif
